/*
 * Copyright (C) 2010 Ryan Morton
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.games.rm.patternpuzzler;

import java.util.ArrayList;
import java.util.HashMap;

import android.content.Context;
import android.media.MediaPlayer;
import android.os.Handler;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Animation.AnimationListener;
import android.widget.ImageView;

public class PatternPlayer implements AnimationListener
{
	private HashMap<Integer, ImageView> lightedButtonMap;
	HashMap<ImageView, MediaPlayer> soundCache;
	private ArrayList<Integer> myPattern;
	private int currentPatternIndex;
	private Handler myHandler;
	private GameBoard4 myParent4;
	private Context myContext;
	private ImageView myLight;
	private GameBoard5 myParent5;
	private Animation lightAnimation;
	private boolean cancelPlay;
	private boolean patternSpeedsUp;
	private boolean isRepeat = false;
	
	private int BUTTON_DISPLAY_TIME = 600;//time in ms
	private int BUTTON_DISPLAY_DELAY = 100;//time (in ms) between lighted buttons in the pattern
	private static final int BUTTON_DISPLAY_TIME_MIN = 50;//min time in ms
	private static final int BUTTON_DISPLAY_DELAY_MIN = 50;//min time (in ms) between lighted buttons in the pattern
	
	/***
	 * Use this to decrease the display time of button presses in the pattern (decreases 10 ms w/each call)
	 */
	public void decreaseButtonDisplayTime()
	{
		if(BUTTON_DISPLAY_TIME>BUTTON_DISPLAY_TIME_MIN)
		{
			BUTTON_DISPLAY_TIME-=50;
			//System.out.println(BUTTON_DISPLAY_TIME);
		}
	}
	
	/***
	 * Use this to decrease the time between button presses in the pattern (decreases 10 ms w/each call)
	 */
	public void decreaseButtonDisplayDelay()
	{
		if(BUTTON_DISPLAY_DELAY>BUTTON_DISPLAY_DELAY_MIN)
		{
			BUTTON_DISPLAY_DELAY-=10;
		}
	}
	
	public PatternPlayer(boolean speedsUp, HashMap<Integer, ImageView> buttonMap,
			HashMap<ImageView, MediaPlayer> patternPlayerSoundCache, GameBoard4 parent, Handler h) 
	{
		lightedButtonMap = buttonMap;
		myPattern = new ArrayList<Integer>();
		soundCache = patternPlayerSoundCache;
		currentPatternIndex = 0;
		myHandler = h;
		myParent4 = parent;
		myContext = parent;
		cancelPlay = false;
		patternSpeedsUp = speedsUp;
	}
	
	public PatternPlayer(boolean speedsUp, HashMap<Integer, ImageView> buttonMap,
			HashMap<ImageView, MediaPlayer> patternPlayerSoundCache, GameBoard5 parent, Handler h) 
	{
		lightedButtonMap = buttonMap;
		myPattern = new ArrayList<Integer>();
		soundCache = patternPlayerSoundCache;
		currentPatternIndex = 0;
		myHandler = h;
		myParent5 = parent;
		myContext = parent;
		cancelPlay = false;
		patternSpeedsUp = speedsUp;
	}
	
	/**
	 * add an int, representing the button number, to the pattern
	 */
	public void add(int button)
	{
		myPattern.add(button);
	}
	
	/**
	 * 
	 * @return an ArrayList<Integer> that represents the button pattern
	 */
	public ArrayList<Integer> getPattern()
	{
		return this.myPattern;
	}
	
	/***
	 * 
	 * @param pattern an ArrayList<Integer> that represents the button pattern
	 */
	public void setPattern(ArrayList<Integer> pattern)
	{
		myPattern = pattern;
	}
	
	/**
	 * Starts the display of the pattern. Each buttons will fade-in in 20ms, be displayed for 1000ms (1 sec.), and then
	 * fade-out in 20ms. The fade-out animation triggers the next button animation in the pattern.
	 */
	public void playPattern(boolean repeat)
	{
		if(!cancelPlay)
		{
			isRepeat = repeat;
			myLight = lightedButtonMap.get(myPattern.get(currentPatternIndex));
			currentPatternIndex++;
			
			//set the fade-in animation, and the listener to trigger the fade-out animation after BUTTON_DISPLAY_TIME
			//the fade-out animation should have this as the listener, so it can trigger the next button in the pattern
			lightAnimation = AnimationUtils.loadAnimation(myContext, R.anim.fade_in_20);
			lightAnimation.setAnimationListener(new AnimationListener() {
				
				@Override
				public void onAnimationStart(Animation animation){}
				
				@Override
				public void onAnimationRepeat(Animation animation){}
				
				@Override
				public void onAnimationEnd(Animation animation)
				{
					//set the fade-out animation, and the listener to this in order to trigger the next button in the pattern 
					lightAnimation = AnimationUtils.loadAnimation(myContext, R.anim.fade_out_20);
					lightAnimation.setAnimationListener(PatternPlayer.this);
					myHandler.postDelayed(new Runnable() {
						
						@Override
						public void run()
						{
							myLight.startAnimation(lightAnimation);
						}
					}, BUTTON_DISPLAY_TIME);
				}
			});
			
			myHandler.postDelayed(new Runnable() {
				
				@Override
				public void run()
				{
					//play the tone
					try
					{
						if(myParent4 != null)
						{
							if(myParent4.isSoundOn())
							{
								soundCache.get(myLight).start();
							}
						}
						else
						{
							if(myParent5.isSoundOn())
							{
								soundCache.get(myLight).start();
							}
						}
					}
					catch(Exception e)
					{
						//nothing
					}
					
					myLight.setVisibility(View.VISIBLE);
					myLight.startAnimation(lightAnimation);
				}
			}, BUTTON_DISPLAY_DELAY);
		}
		else
		{
			currentPatternIndex =0;
			cancelPlay = false;
			isRepeat = false;
		}
	}

	/***
	 * Use this to cancel playback of the pattern and tones... cancels the playback even in the middle of
	 * the pattern display
	 */
	public void cancelPlayback()
	{
		cancelPlay = true;
		isRepeat = false;
		try
		{
			for (MediaPlayer mp : soundCache.values())
			{
				if(mp.isPlaying())
				{
					mp.pause();
				}
			}
		}
		catch (Exception e)
		{
			//nothing
		}
	}
	
	@Override
	public void onAnimationEnd(Animation animation)
	{
		myLight.setVisibility(View.INVISIBLE);
		//stop the tone
		try
		{
			if(soundCache.get(myLight).isPlaying())
			{
				soundCache.get(myLight).pause();
			}
		}
		catch (Exception e)
		{
			//nothing
		}
		
		if(currentPatternIndex == myPattern.size())
		{
			//done playing the pattern	
			currentPatternIndex = 0;
			myLight = null;
			
			myHandler.post(new Runnable() {
				
				@Override
				public void run()
				{
					if(myParent4!= null)
					{
						myParent4.startGame();
					}
					else if(myParent5!= null)
					{
						myParent5.startGame();
					}
				}
			});
			
			//decrease the display time and delay if nec.
			if(patternSpeedsUp && !isRepeat)
			{
				this.decreaseButtonDisplayDelay();
				this.decreaseButtonDisplayTime();
			}
		}
		else
		{
			if(!cancelPlay)
			{
				myLight = lightedButtonMap.get(myPattern.get(currentPatternIndex));
				
				//set the fade-in animation, and the listener to trigger the fade-out animation after BUTTON_DISPLAY_TIME
				//the fade-out animation should have this as the listener, so it can trigger the next button in the pattern
				lightAnimation = AnimationUtils.loadAnimation(myContext, R.anim.fade_in_20);
				lightAnimation.setAnimationListener(new AnimationListener() {
					
					@Override
					public void onAnimationStart(Animation animation){}
					
					@Override
					public void onAnimationRepeat(Animation animation){}
					
					@Override
					public void onAnimationEnd(Animation animation){
						//set the fade-out animation, and the listener to this in order to trigger the next button in the pattern 
						lightAnimation = AnimationUtils.loadAnimation(myContext, R.anim.fade_out_20);
						lightAnimation.setAnimationListener(PatternPlayer.this);
						myHandler.postDelayed(new Runnable() {
							
							@Override
							public void run()
							{
								myLight.startAnimation(lightAnimation);
							}
						}, BUTTON_DISPLAY_TIME);
					}
				});
				
				myHandler.postDelayed(new Runnable() {
					
					@Override
					public void run()
					{
						//play the tone
						try
						{
							if(myParent4 != null)
							{
								if(myParent4.isSoundOn())
								{
									soundCache.get(myLight).start();
								}
							}
							else
							{
								if(myParent5.isSoundOn())
								{
									soundCache.get(myLight).start();
								}
							}
						}
						catch (Exception e)
						{
							//nothing
						}
						
						myLight.setVisibility(View.VISIBLE);
						myLight.startAnimation(lightAnimation);
					}
				}, BUTTON_DISPLAY_DELAY);
				
				currentPatternIndex++;
			}
			else
			{
				currentPatternIndex = 0;
				cancelPlay = false;
				isRepeat = false;
			}
		}
	}

	@Override
	public void onAnimationRepeat(Animation animation){}

	@Override
	public void onAnimationStart(Animation animation){}
}
